package com.dhcc.bpm.common.segmentId;

import com.dhcc.bpm.common.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.atomic.AtomicLong;

/**
 * @description id生成服务
 * @author guogang
 * @date 2020年7月15日 上午8:55:17
 * @version 1.0.0
 */
@Service
public class IdGeneratorService {
	private static final Logger log = LoggerFactory.getLogger(IdGeneratorService.class);
	private final static double loadFactor = 0.2; // 装填因子
	public static final int RETRY = 3; // 重试次数
	@Autowired
	OpcSegmentIdMapper opcSegmentIdMapper;
	/**
	 * @description 通过业务类型获取分段 @Transactional(isolation = Isolation.READ_COMMITTED)
	 *              避免脏读
	 * @date 2020年7月15日 上午8:59:11
	 * @param bizType
	 *            业务类型
	 * @return SegmentId 分段id
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public SegmentId nextSegmentId(String bizType) {
		// 获取nextTinyId的时候，有可能存在version冲突，需要重试
		SegmentId segmentId = null;
		for (int i = 0; i < RETRY; i++) {
			log.info("查询分段SegmentId...");
			segmentId = opcSegmentIdMapper.findByBizType(bizType);
			log.info("查询分段[{}]", segmentId);
			if (segmentId == null) {
				log.error("获取分段 segmentId[{}]", segmentId);
				throw new BusinessException("获取分段segmentId为空");
			} else { // 更新业务Max_id
				long nowMaxId = segmentId.getMaxId() + segmentId.getStep();
				// 时间回退
				if(segmentId.getCurDate().compareTo(segmentId.getNewDate())>0) {
					log.error("数据库时间回退！！！！");
					throw new BusinessException("数据库时间回退");
				}
				if(segmentId.getCurDate().equals(segmentId.getNewDate())&&nowMaxId > segmentId.getIdLimit()) {
					log.error("当日流水超出分段超出！！！");
					throw new BusinessException("当日流水超出分段超出");
				}
				//日期变动为第二天
				if (segmentId.getCurDate().compareTo(segmentId.getNewDate())<0) {
					int row = opcSegmentIdMapper.updateMaxIdAndDayByBizType(bizType, segmentId.getVersion());
					if (row == 1) {
						segmentId.setCurrentId(new AtomicLong(0L));
						segmentId.setLoadingId(
								segmentId.getMaxId() + Double.valueOf(segmentId.getStep() * loadFactor).longValue());
						segmentId.setMaxId(segmentId.getStep());
						segmentId.setCurDate(segmentId.getNewDate());
						segmentId.setLen(String.valueOf(segmentId.getIdLimit()).length());
						log.info("获取分段[{}]", segmentId);
						return segmentId;
					} else {
						log.info("更新分段冲突,重试" + (i + 1) + "次");
					}

				} else {
					int row = opcSegmentIdMapper.updateMaxIdByBizType(bizType, segmentId.getVersion());
					if (row == 1) {
						segmentId.setCurrentId(new AtomicLong(segmentId.getMaxId()));
						segmentId.setLoadingId(
								segmentId.getMaxId() + Double.valueOf(segmentId.getStep() * loadFactor).longValue());
						segmentId.setMaxId(nowMaxId);
						segmentId.setCurDate(segmentId.getNewDate());
						segmentId.setLen(String.valueOf(segmentId.getIdLimit()).length());
						log.info("获取分段[{}]", segmentId);
						return segmentId;
					} else {
						log.info("更新分段冲突,重试" + (i + 1) + "次");
					}
				}
			}
		}
		throw new BusinessException("获取分段异常");
	}

	/**
	 * @description 获取数据库最新时间
	 * @date 2020年7月19日 上午8:32:09
	 * @return
	 */
	public String getDataSouceSysDate() {
		return opcSegmentIdMapper.findDataSouceSysDate();
	}

	/**
	 * @description 获取当前分段
	 * @date 2020年7月19日 上午8:32:09
	 * @return
	 */
	public SegmentId getCurSegmentId(String bizType) {
		return opcSegmentIdMapper.findByBizType(bizType);
	}
}
